"""
Ansible Management Views
"""
import json
import tempfile
import subprocess
import yaml
from datetime import datetime
from rest_framework import viewsets, status
from rest_framework.decorators import action, api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from django.utils import timezone
from django.db import models

from .models import AnsibleInventory, AnsibleCredential, AnsiblePlaybook, AnsibleJob
from .serializers import (
    AnsibleInventorySerializer, AnsibleCredentialSerializer,
    AnsiblePlaybookSerializer, AnsibleJobSerializer
)


# 辅助函数
def check_playbook_syntax(content):
    """检查Playbook语法"""
    try:
        yaml.safe_load(content)
        return {'valid': True, 'message': '语法检查通过'}
    except yaml.YAMLError as e:
        return {'valid': False, 'message': f'YAML语法错误: {str(e)}'}


class AnsibleInventoryViewSet(viewsets.ModelViewSet):
    """Ansible清单ViewSet"""
    queryset = AnsibleInventory.objects.all()
    serializer_class = AnsibleInventorySerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        """用户只能看到自己创建的或共享的清单"""
        user = self.request.user
        if user.is_superuser:
            return AnsibleInventory.objects.all()
        return AnsibleInventory.objects.filter(created_by=user)


class AnsibleCredentialViewSet(viewsets.ModelViewSet):
    """Ansible凭据ViewSet"""
    queryset = AnsibleCredential.objects.all()
    serializer_class = AnsibleCredentialSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        """用户只能看到自己创建的凭据"""
        user = self.request.user
        if user.is_superuser:
            return AnsibleCredential.objects.all()
        return AnsibleCredential.objects.filter(created_by=user)


class AnsiblePlaybookViewSet(viewsets.ModelViewSet):
    """Ansible Playbook ViewSet"""
    queryset = AnsiblePlaybook.objects.all()
    serializer_class = AnsiblePlaybookSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        """用户可以看到所有激活的playbook和自己创建的playbook"""
        user = self.request.user
        if user.is_superuser:
            return AnsiblePlaybook.objects.all()
        return AnsiblePlaybook.objects.filter(
            models.Q(status='active') | models.Q(created_by=user)
        )
    
    def perform_create(self, serializer):
        """创建时自动设置创建者"""
        serializer.save(created_by=self.request.user)
    
    @action(detail=False, methods=['post'])
    def upload_to_host(self, request):
        """上传Playbook文件到目标主机"""
        import paramiko
        from io import StringIO
        
        content = request.data.get('content')
        filename = request.data.get('filename', 'playbook.yml')
        target_host_id = request.data.get('target_host')
        remote_path = request.data.get('remote_path', '/tmp')
        
        if not content or not target_host_id:
            return Response(
                {'error': '缺少必要参数：content和target_host'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            from cmdb.models import Host
            host = Host.objects.get(id=target_host_id)
        except Host.DoesNotExist:
            return Response(
                {'error': '目标主机不存在'},
                status=status.HTTP_404_NOT_FOUND
            )
        
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # SSH连接
            if host.auth_type == 'password':
                ssh.connect(host.ip, port=host.port, username=host.username, 
                           password=host.password, timeout=10)
            else:
                key_file = StringIO(host.ssh_key)
                pkey = paramiko.RSAKey.from_private_key(key_file)
                ssh.connect(host.ip, port=host.port, username=host.username, 
                           pkey=pkey, timeout=10)
            
            # 确保目录存在
            sftp = ssh.open_sftp()
            try:
                sftp.stat(remote_path)
            except FileNotFoundError:
                # 创建目录
                stdin, stdout, stderr = ssh.exec_command(f'mkdir -p {remote_path}')
                stdout.channel.recv_exit_status()
            
            # 上传文件
            remote_file_path = f"{remote_path}/{filename}"
            with sftp.file(remote_file_path, 'w') as f:
                f.write(content)
            
            sftp.close()
            ssh.close()
            
            return Response({
                'message': '文件上传成功',
                'remote_path': remote_file_path,
                'host': f"{host.name} ({host.ip})"
            })
            
        except Exception as e:
            return Response(
                {'error': f'上传失败: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    @action(detail=False, methods=['post'])
    def list_remote_files(self, request):
        """列出目标主机指定目录的内容（文件夹和YAML文件）"""
        import paramiko
        from io import StringIO
        
        target_host_id = request.data.get('target_host')
        remote_path = request.data.get('remote_path', '/')
        
        if not target_host_id:
            return Response(
                {'error': '缺少参数：target_host'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            from cmdb.models import Host
            host = Host.objects.get(id=target_host_id)
        except Host.DoesNotExist:
            return Response(
                {'error': '目标主机不存在'},
                status=status.HTTP_404_NOT_FOUND
            )
        
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # SSH连接
            if host.auth_type == 'password':
                ssh.connect(host.ip, port=host.port, username=host.username, 
                           password=host.password, timeout=10)
            else:
                key_file = StringIO(host.ssh_key)
                pkey = paramiko.RSAKey.from_private_key(key_file)
                ssh.connect(host.ip, port=host.port, username=host.username, 
                           pkey=pkey, timeout=10)
            
            sftp = ssh.open_sftp()
            
            # 确保路径存在
            try:
                sftp.stat(remote_path)
            except FileNotFoundError:
                ssh.close()
                return Response(
                    {'error': f'路径不存在: {remote_path}'},
                    status=status.HTTP_404_NOT_FOUND
                )
            
            # 列出目录内容
            items = sftp.listdir_attr(remote_path)
            
            directories = []
            yaml_files = []
            
            for item in items:
                item_path = f"{remote_path.rstrip('/')}/{item.filename}"
                
                # 判断是否为目录
                if item.st_mode & 0o040000:  # 目录
                    directories.append({
                        'name': item.filename,
                        'path': item_path,
                        'type': 'directory',
                        'size': item.st_size
                    })
                # 判断是否为YAML文件
                elif item.filename.endswith(('.yml', '.yaml')):
                    yaml_files.append({
                        'name': item.filename,
                        'path': item_path,
                        'type': 'file',
                        'size': item.st_size
                    })
            
            sftp.close()
            ssh.close()
            
            # 排序：目录在前，文件在后
            directories.sort(key=lambda x: x['name'])
            yaml_files.sort(key=lambda x: x['name'])
            
            return Response({
                'current_path': remote_path,
                'directories': directories,
                'files': yaml_files,
                'total': len(directories) + len(yaml_files)
            })
            
        except Exception as e:
            return Response(
                {'error': f'获取目录内容失败: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    @action(detail=False, methods=['post'])
    def read_remote_file(self, request):
        """读取目标主机上的文件内容"""
        import paramiko
        from io import StringIO
        
        target_host_id = request.data.get('target_host')
        file_path = request.data.get('file_path')
        
        if not target_host_id or not file_path:
            return Response(
                {'error': '缺少必要参数：target_host和file_path'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            from cmdb.models import Host
            host = Host.objects.get(id=target_host_id)
        except Host.DoesNotExist:
            return Response(
                {'error': '目标主机不存在'},
                status=status.HTTP_404_NOT_FOUND
            )
        
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # SSH连接
            if host.auth_type == 'password':
                ssh.connect(host.ip, port=host.port, username=host.username, 
                           password=host.password, timeout=10)
            else:
                key_file = StringIO(host.ssh_key)
                pkey = paramiko.RSAKey.from_private_key(key_file)
                ssh.connect(host.ip, port=host.port, username=host.username, 
                           pkey=pkey, timeout=10)
            
            # 读取文件
            sftp = ssh.open_sftp()
            with sftp.file(file_path, 'r') as f:
                content = f.read().decode('utf-8')
            
            sftp.close()
            ssh.close()
            
            return Response({
                'content': content,
                'file_path': file_path,
                'filename': file_path.split('/')[-1]
            })
            
        except Exception as e:
            return Response(
                {'error': f'读取文件失败: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    @action(detail=False, methods=['post'])
    def execute_content(self, request):
        """直接执行Playbook内容（在Ansible控制节点上执行）"""
        import paramiko
        import tempfile
        import uuid
        from io import StringIO
        
        content = request.data.get('content')
        inventory_id = request.data.get('inventory')
        credential_id = request.data.get('credential')
        
        if not content:
            return Response(
                {'error': '缺少Playbook内容'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        if not inventory_id or not credential_id:
            return Response(
                {'error': '请选择主机清单和凭据'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            inventory = AnsibleInventory.objects.get(id=inventory_id)
            credential = AnsibleCredential.objects.get(id=credential_id)
        except (AnsibleInventory.DoesNotExist, AnsibleCredential.DoesNotExist) as e:
            return Response(
                {'error': f'清单或凭据不存在: {str(e)}'},
                status=status.HTTP_404_NOT_FOUND
            )
        
        # 真正执行Ansible Playbook
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            
            # 连接到Ansible控制节点
            if credential.credential_type == 'ssh_password':
                ssh.connect(
                    inventory.host_address, 
                    port=inventory.ssh_port,
                    username=inventory.ssh_user, 
                    password=credential.password,
                    timeout=10
                )
            else:  # ssh_key
                key_file = StringIO(credential.ssh_key)
                pkey = paramiko.RSAKey.from_private_key(key_file)
                ssh.connect(
                    inventory.host_address, 
                    port=inventory.ssh_port,
                    username=inventory.ssh_user,
                    pkey=pkey,
                    timeout=10
                )
            
            # 生成临时文件名
            playbook_filename = f"playbook_{uuid.uuid4().hex[:8]}.yml"
            remote_playbook_path = f"/tmp/{playbook_filename}"
            
            # 上传Playbook内容
            sftp = ssh.open_sftp()
            with sftp.file(remote_playbook_path, 'w') as f:
                f.write(content)
            sftp.close()
            
            # 构建ansible-playbook命令
            inventory_path = inventory.inventory_path or '/etc/ansible/hosts'
            
            # 执行ansible-playbook
            cmd = f"ansible-playbook -i {inventory_path} {remote_playbook_path}"
            
            stdin, stdout, stderr = ssh.exec_command(cmd)
            exit_status = stdout.channel.recv_exit_status()
            
            stdout_text = stdout.read().decode('utf-8')
            stderr_text = stderr.read().decode('utf-8')
            
            # 清理临时文件
            ssh.exec_command(f"rm -f {remote_playbook_path}")
            
            ssh.close()
            
            # 创建任务历史记录
            start = timezone.now()
            end = timezone.now()
            job = AnsibleJob.objects.create(
                job_type='playbook',
                playbook=None,  # 在线执行的playbook，不关联已保存的playbook
                inventory=inventory,
                credential=credential,
                target_hosts='在线执行',
                status='success' if exit_status == 0 else 'failed',
                stdout=stdout_text,
                stderr=stderr_text if stderr_text else '',
                result=content[:200] + '...' if len(content) > 200 else content,  # 保存playbook内容摘要
                duration='',
                start_time=start,
                end_time=end,
                created_by=request.user
            )
            
            # 返回结果
            return Response({
                'status': 'success' if exit_status == 0 else 'failed',
                'stdout': stdout_text,
                'stderr': stderr_text,
                'exit_code': exit_status,
                'message': '执行成功' if exit_status == 0 else '执行失败',
                'job_id': job.id
            })
            
        except paramiko.AuthenticationException as e:
            # 保存失败任务记录
            AnsibleJob.objects.create(
                job_type='playbook',
                inventory=inventory,
                credential=credential,
                target_hosts='在线执行',
                status='failed',
                stderr=f'SSH认证失败: {str(e)}',
                result=content[:200] + '...' if len(content) > 200 else content,
                duration='',
                start_time=timezone.now(),
                end_time=timezone.now(),
                created_by=request.user
            )
            return Response(
                {'error': 'SSH认证失败，请检查凭据配置'},
                status=status.HTTP_401_UNAUTHORIZED
            )
        except paramiko.SSHException as e:
            # 保存失败任务记录
            AnsibleJob.objects.create(
                job_type='playbook',
                inventory=inventory,
                credential=credential,
                target_hosts='在线执行',
                status='failed',
                stderr=f'SSH连接错误: {str(e)}',
                result=content[:200] + '...' if len(content) > 200 else content,
                duration='',
                start_time=timezone.now(),
                end_time=timezone.now(),
                created_by=request.user
            )
            return Response(
                {'error': f'SSH连接错误: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        except Exception as e:
            # 保存失败任务记录
            AnsibleJob.objects.create(
                job_type='playbook',
                inventory=inventory if 'inventory' in locals() else None,
                credential=credential if 'credential' in locals() else None,
                target_hosts='在线执行',
                status='failed',
                stderr=f'执行失败: {str(e)}',
                result=content[:200] + '...' if len(content) > 200 else content,
                duration='',
                start_time=timezone.now(),
                end_time=timezone.now(),
                created_by=request.user
            )
            return Response(
                {'error': f'执行失败: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    @action(detail=True, methods=['post'])
    def execute(self, request, pk=None):
        """执行Playbook"""
        playbook = self.get_object()
        inventory_id = request.data.get('inventory_id', playbook.inventory_id)
        credential_id = request.data.get('credential_id', playbook.credential_id)
        extra_vars = request.data.get('extra_vars', {})
        
        if not inventory_id or not credential_id:
            return Response(
                {'error': '请选择主机清单和凭据'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            inventory = AnsibleInventory.objects.get(id=inventory_id)
            credential = AnsibleCredential.objects.get(id=credential_id)
        except (AnsibleInventory.DoesNotExist, AnsibleCredential.DoesNotExist):
            return Response(
                {'error': '清单或凭据不存在'},
                status=status.HTTP_404_NOT_FOUND
            )
        
        # 创建任务
        job = AnsibleJob.objects.create(
            job_type='playbook',
            playbook=playbook,
            inventory=inventory,
            credential=credential,
            extra_vars=extra_vars,
            created_by=request.user,
            status='pending'
        )
        
        # 异步执行（这里简化处理，实际应该用Celery）
        try:
            job.status = 'running'
            job.start_time = timezone.now()
            job.save()
            
            result = execute_playbook_task(playbook, inventory, credential, extra_vars)
            
            job.status = 'success' if result['success'] else 'failed'
            job.stdout = result.get('stdout', '')
            job.stderr = result.get('stderr', '')
            job.result = json.dumps(result.get('result', {}))
            job.end_time = timezone.now()
            job.save()
            
            return Response(AnsibleJobSerializer(job).data)
        except Exception as e:
            job.status = 'failed'
            job.stderr = str(e)
            job.end_time = timezone.now()
            job.save()
            return Response(
                {'error': f'执行失败: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    @action(detail=False, methods=['post'])
    def syntax_check(self, request):
        """语法检查"""
        content = request.data.get('content', '')
        if not content:
            return Response(
                {'error': 'Playbook内容不能为空'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        try:
            result = check_playbook_syntax(content)
            return Response(result)
        except Exception as e:
            return Response(
                {'error': f'语法检查失败: {str(e)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


class AnsibleJobViewSet(viewsets.ModelViewSet):
    """Ansible任务ViewSet - 支持删除"""
    queryset = AnsibleJob.objects.all()
    serializer_class = AnsibleJobSerializer
    permission_classes = [IsAuthenticated]
    
    def get_queryset(self):
        """用户只能看到自己创建的任务"""
        user = self.request.user
        if user.is_superuser:
            return AnsibleJob.objects.all()
        return AnsibleJob.objects.filter(created_by=user)
    
    @action(detail=True, methods=['post'])
    def cancel(self, request, pk=None):
        """取消任务"""
        job = self.get_object()
        if job.status in ['pending', 'running']:
            job.status = 'canceled'
            job.end_time = timezone.now()
            job.save()
            return Response({'message': '任务已取消'})
        return Response(
            {'error': '只能取消等待中或运行中的任务'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    @action(detail=False, methods=['post'])
    def bulk_delete(self, request):
        """批量删除任务"""
        ids = request.data.get('ids', [])
        if not ids:
            return Response(
                {'error': '未提供任务ID'},
                status=status.HTTP_400_BAD_REQUEST
            )
        
        # 只能删除自己的任务，除非是超级管理员
        user = request.user
        if user.is_superuser:
            jobs = AnsibleJob.objects.filter(id__in=ids)
        else:
            jobs = AnsibleJob.objects.filter(id__in=ids, created_by=user)
        
        count = jobs.count()
        jobs.delete()
        
        return Response({
            'message': f'成功删除 {count} 个任务',
            'deleted_count': count
        })


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def execute_adhoc(request):
    """执行Ad-hoc命令（在Ansible控制节点上执行）"""
    import paramiko
    import uuid
    from io import StringIO
    
    inventory_id = request.data.get('inventory') or request.data.get('inventory_id')
    credential_id = request.data.get('credential') or request.data.get('credential_id')
    module = request.data.get('module', 'ping')
    args = request.data.get('args', '')
    host_pattern = request.data.get('host_pattern', 'all')
    
    if not all([inventory_id, credential_id]):
        return Response(
            {'error': '请提供清单和凭据'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    try:
        inventory = AnsibleInventory.objects.get(id=inventory_id)
        credential = AnsibleCredential.objects.get(id=credential_id)
    except (AnsibleInventory.DoesNotExist, AnsibleCredential.DoesNotExist):
        return Response(
            {'error': '清单或凭据不存在'},
            status=status.HTTP_404_NOT_FOUND
        )
    
    # 真正执行Ansible Ad-hoc命令
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        
        # 连接到Ansible控制节点（使用credential的认证信息）
        try:
            print(f"🔍 调试信息:")
            print(f"  - Inventory地址: {inventory.host_address}")
            print(f"  - SSH端口: {inventory.ssh_port}")
            print(f"  - SSH用户: {inventory.ssh_user}")
            print(f"  - Credential类型: {credential.credential_type}")
            print(f"  - Credential名称: {credential.name}")
            print(f"  - 是否有密码: {'是' if credential.password else '否'}")
            print(f"  - 是否有密钥: {'是' if credential.ssh_key else '否'}")
            
            if credential.credential_type == 'ssh_password':
                print(f"  ✅ 使用密码认证")
                ssh.connect(
                    inventory.host_address, 
                    port=inventory.ssh_port,
                    username=inventory.ssh_user, 
                    password=credential.password,
                    timeout=10
                )
            else:  # ssh_key
                print(f"  ✅ 使用密钥认证")
                key_file = StringIO(credential.ssh_key)
                pkey = paramiko.RSAKey.from_private_key(key_file)
                ssh.connect(
                    inventory.host_address, 
                    port=inventory.ssh_port,
                    username=inventory.ssh_user,
                    pkey=pkey,
                    timeout=10
                )
            print(f"  ✅ SSH连接成功!")
        except Exception as conn_error:
            print(f"  ❌ SSH连接失败: {str(conn_error)}")
            return Response(
                {'error': f'SSH连接失败: {str(conn_error)}'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
        
        # 构建ansible命令
        inventory_path = inventory.inventory_path or '/etc/ansible/hosts'
        cmd = f"ansible {host_pattern} -i {inventory_path} -m {module}"
        
        if args:
            # 转义特殊字符
            args_escaped = args.replace('"', '\\"')
            cmd += f' -a "{args_escaped}"'
        
        print(f"执行命令: {cmd}")  # 调试日志
        
        # 执行命令
        stdin, stdout, stderr = ssh.exec_command(cmd, timeout=30)
        exit_status = stdout.channel.recv_exit_status()
        
        stdout_text = stdout.read().decode('utf-8', errors='ignore')
        stderr_text = stderr.read().decode('utf-8', errors='ignore')
        
        print(f"退出状态: {exit_status}")  # 调试日志
        print(f"标准输出: {stdout_text[:200]}")  # 调试日志
        print(f"错误输出: {stderr_text[:200]}")  # 调试日志
        
        ssh.close()
        
        # 创建任务历史记录
        job = AnsibleJob.objects.create(
            job_type='adhoc',
            module=module,
            args=args,
            inventory=inventory,
            credential=credential,
            target_hosts=host_pattern,
            status='success' if exit_status == 0 else 'failed',
            stdout=stdout_text,
            stderr=stderr_text if stderr_text else '',
            duration='',
            start_time=timezone.now(),
            end_time=timezone.now(),
            created_by=request.user
        )
        
        # 返回结果
        return Response({
            'success': exit_status == 0,
            'stdout': stdout_text,
            'stderr': stderr_text if stderr_text else '',
            'exit_code': exit_status,
            'command': cmd,
            'job_id': job.id
        })
        
    except paramiko.AuthenticationException as auth_error:
        # 保存失败任务记录
        AnsibleJob.objects.create(
            job_type='adhoc',
            module=module,
            args=args,
            inventory=inventory,
            credential=credential,
            target_hosts=host_pattern,
            status='failed',
            stderr=f'SSH认证失败: {str(auth_error)}',
            duration='',
            start_time=timezone.now(),
            end_time=timezone.now(),
            created_by=request.user
        )
        return Response(
            {'error': f'SSH认证失败: {str(auth_error)}'},
            status=status.HTTP_401_UNAUTHORIZED
        )
    except paramiko.SSHException as ssh_error:
        # 保存失败任务记录
        AnsibleJob.objects.create(
            job_type='adhoc',
            module=module,
            args=args,
            inventory=inventory,
            credential=credential,
            target_hosts=host_pattern,
            status='failed',
            stderr=f'SSH连接错误: {str(ssh_error)}',
            duration='',
            start_time=timezone.now(),
            end_time=timezone.now(),
            created_by=request.user
        )
        return Response(
            {'error': f'SSH连接错误: {str(ssh_error)}'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )
    except Exception as e:
        import traceback
        error_detail = traceback.format_exc()
        print(f"执行失败详情: {error_detail}")  # 调试日志
        # 保存失败任务记录
        AnsibleJob.objects.create(
            job_type='adhoc',
            module=module,
            args=args,
            inventory=inventory if 'inventory' in locals() else None,
            credential=credential if 'credential' in locals() else None,
            target_hosts=host_pattern,
            status='failed',
            stderr=f'执行失败: {str(e)}',
            duration='',
            start_time=timezone.now(),
            end_time=timezone.now(),
            created_by=request.user
        )
        return Response(
            {'error': f'执行失败: {str(e)}'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR
        )


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def get_ansible_modules(request):
    """获取Ansible模块列表（用于自动补全）"""
    modules = [
        {'name': 'ping', 'description': '测试主机连接'},
        {'name': 'shell', 'description': '执行Shell命令'},
        {'name': 'command', 'description': '执行命令'},
        {'name': 'copy', 'description': '复制文件'},
        {'name': 'file', 'description': '管理文件和目录'},
        {'name': 'template', 'description': '模板文件'},
        {'name': 'yum', 'description': 'YUM包管理'},
        {'name': 'apt', 'description': 'APT包管理'},
        {'name': 'service', 'description': '管理服务'},
        {'name': 'systemd', 'description': 'Systemd服务管理'},
        {'name': 'user', 'description': '管理用户'},
        {'name': 'group', 'description': '管理组'},
        {'name': 'git', 'description': 'Git仓库管理'},
        {'name': 'docker_container', 'description': 'Docker容器管理'},
        {'name': 'mysql_db', 'description': 'MySQL数据库管理'},
    ]
    
    search = request.query_params.get('search', '')
    if search:
        modules = [m for m in modules if search.lower() in m['name'].lower()]
    
    return Response(modules)


def execute_playbook_task(playbook, inventory, credential, extra_vars):
    """执行Playbook任务（实际实现）"""
    # 这里是简化版本，实际应该：
    # 1. 创建临时inventory文件
    # 2. 创建临时playbook文件
    # 3. 使用ansible-playbook命令执行
    # 4. 解析输出结果
    
    # 模拟执行
    return {
        'success': True,
        'stdout': 'PLAY [Example Play] *****\n\nTASK [Gathering Facts] *****\nok: [host1]\n\nPLAY RECAP *****\nhost1: ok=1 changed=0',
        'stderr': '',
        'result': {'ok': 1, 'changed': 0, 'unreachable': 0, 'failed': 0}
    }


def execute_adhoc_task(inventory, credential, module, args):
    """执行Ad-hoc任务（实际实现）"""
    # 模拟执行
    return {
        'success': True,
        'stdout': f'{module} executed successfully with args: {args}',
        'stderr': '',
        'result': {'success': True}
    }
